﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using KC.DataAccess.BuggerAll;

namespace KC.Business.Bugs
{
	#region Enums
	/// <summary>Known ProjectIDs in BuggerAll database</summary>
	public enum KnownProject
	{
		Invalid = 0,
		BuggerAll = 1,
		MV7 = 2,
		ArchitectureMonitor = 3,
		KCArchitecture = 5,
		PersonalSharepointPortal = 6,
		WorkTool = 7,
		META = 8
	}
	/// <summary>Known BugPriorities in BuggerAll database</summary>
	public enum KnownPriority
	{
		Invalid = 0,
		Critical = 1,
		Important = 2,
		WouldBeNice = 3,
		Planned = 4
	}
	/// <summary>Known BugCategories in BuggerAll database</summary>
	public enum KnownCategory
	{
		Invalid = 0,
		General = 1,
		AutoGenerated = 2
	}
	/// <summary>Known BugStatuses in BuggerAll database</summary>
	public enum KnownStatus
	{
		Invalid = 0,
		Open = 1,
		Closed = 3,
		WillNotFix = 4,
		New = 6
	}
	/// <summary>Known BugStatusChangeReasons in BuggerAll database</summary>
	public enum KnownStatusChangeReason
	{
		Invalid = 0,
		Created = 1,
		Modified = 2,
		Closed = 3,
		Reopened = 4
	}
	#endregion Enums

	public static class BugLogger
	{
		public const int UserID = 1; //TODO: KC.Constants.GlobalConstants.KCArchitecture_BuggerAllUserID;

		/// <summary>Writes a Bug to the BuggerAll database.</summary>
		/// <param name="Category">BugCategory</param>
		/// <param name="Priority">BugPriority</param>
		/// <param name="Project">BuggerAll Project</param>
		/// <param name="Description">Description of Bug</param>
		/// <param name="Detail">Detail of Bug</param>
		/// <param name="DebugInfoID">ID of related DebugInfoID (Recommended)</param>
		public static void Write(KnownCategory Category, KnownPriority Priority, KnownProject Project, string Description, string Detail, int? DebugInfoID)
		{
			BuggerAllDataContext dc = new BuggerAllDataContext();
			
			Bug b = new Bug();
			b.BugCategory = GetCategory(Category, ref dc);
			b.BugPriority = GetPriority(Priority, ref dc);
			b.Project = GetProject(Project, ref dc);
			b.BugStatuse = GetStatus(KnownStatus.New, ref dc);
			b.DateUpdated = DateTime.Now;
			b.Description = Description;
			b.Detail = Detail;

			if (DebugInfoID != null)
				b.Detail = "(DebugInfo ID = " + DebugInfoID.ToString() + "): " + b.Detail;
			dc.Bugs.InsertOnSubmit(b);
			dc.SubmitChanges();

			// Setup initial status change
			BugStatusChange bs = new BugStatusChange();
			bs.BugID = b.ID;
			bs.Comments = "Created";
			bs.DateTime = DateTime.Now;
			bs.UserId = UserID;
			bs.StatusIdBefore = (from bs1 in dc.BugStatuses
								 where bs1.ID == (Int16)KnownStatus.New
								 select bs1).First().ID;
			bs.StatusIdAfter = b.StatusID;
			bs.ReasonId = (from r in dc.BugStatusChangeReasons
						   where r.ID == (Int16)KnownStatusChangeReason.Created
						   select r).First().ID;

			dc.BugStatusChanges.InsertOnSubmit(bs);
			dc.SubmitChanges();
			dc.Dispose();
		}

		/// <summary>Validates and converts KnownCategory enums into BugCategory objects.</summary>
		/// <param name="Category">KnownCategory value</param>
		/// <param name="dc">BuggerAll DataContext</param>
		/// <returns>Valid BugCategory object</returns>
		/// <exception cref="System.ApplicationException">Thrown if validation fails</exception>
		public static BugCategory GetCategory(KnownCategory Category, ref BuggerAllDataContext dc)
		{
			if (dc == null)
				throw new ArgumentNullException("dc", "Can't use a null datacontext");

			if (Category == KnownCategory.Invalid)
				throw new ArgumentOutOfRangeException("Category", "Cannot log using Invalid Category");

			var cats = from c in dc.BugCategories
					   where c.ID == (int)Category
					   select c;
			if (cats.Count() == 0)
				throw new ArgumentException("No such BugCategory: " + ((int)Category).ToString(), "Category");
			return cats.First();
		}
		/// <summary>Validates and converts KnownPriority enums into BugPriority objects.</summary>
		/// <param name="Priority">KnownPriority value</param>
		/// <param name="dc">BuggerAll DataContext</param>
		/// <returns>Valid BugPriority object</returns>
		/// <exception cref="System.ApplicationException">Thrown if validation fails</exception>
		public static BugPriority GetPriority(KnownPriority Priority, ref BuggerAllDataContext dc)
		{
			if (dc == null)
				throw new ArgumentNullException("dc", "This throw exists just to satisfy CA1062.");
			if (Priority == KnownPriority.Invalid)
				throw new ArgumentOutOfRangeException("Priority", "Cannot log using Invalid Priority");

			var pri = from p in dc.BugPriorities
					  where p.ID == (int)Priority
					  select p;
			if (pri.Count() == 0)
				throw new ArgumentException("No such BugPriority: " + ((int)Priority).ToString());
			return pri.First();
		}
		/// <summary>Validates and converts KnownProject enums into BuggerAll.Project objects.</summary>
		/// <param name="Project">KnownProject value</param>
		/// <param name="dc">BuggerAll DataContext</param>
		/// <returns>Valid Priority object</returns>
		/// <exception cref="System.ApplicationException">Thrown if validation fails</exception>
		public static Project GetProject(KnownProject Project, ref BuggerAllDataContext dc)
		{
			if (Project == KnownProject.Invalid)
				throw new ArgumentOutOfRangeException("Project", "Cannot log using Invalid Project");
			if (dc == null)
				throw new ArgumentNullException("dc", "This throw exists just to satisfy CA1062.");

			var proj = from p in dc.Projects
					   where p.ID == (int)Project
					   select p;
			if (proj.Count() == 0)
				throw new ArgumentException("No such Project: " + ((int)Project).ToString());
			return proj.First();
		}
		/// <summary>Validates and converts KnownStatus enums into BugStatus objects.</summary>
		/// <param name="Status">KnownStatus value</param>
		/// <param name="dc">BuggerAll DataContext</param>
		/// <returns>Valid BugStatus object.</returns>
		public static BugStatuse GetStatus(KnownStatus Status, ref BuggerAllDataContext dc)
		{
			if (Status == KnownStatus.Invalid)
				throw new ArgumentOutOfRangeException("Status", "Cannot use Invalid status");
			if (dc == null)
				throw new ArgumentNullException("dc", "This throw exists just to satisfy CA1062.");

			var stat = from s in dc.BugStatuses
					   where s.ID == (int)Status
					   select s;
			if (stat.Count() == 0)
				throw new ArgumentOutOfRangeException("Status", "No such status: " + ((int)Status).ToString());
			return stat.First();
		}

	}
}
